
import java.applet.*;
import java.awt.event.*;
import java.awt.*;
import java.util.ArrayList;

public class Bomberman extends Applet implements KeyListener {

    private Graphics og;
    private Image offscreen;
    private Image map;
    private User me;
    private Connector connector;
    private BomberGraphics bg;
    private Integer walk[][];
    private ArrayList<Bomb> bombs;
    private ArrayList<Boom> booms;
    private ArrayList<BoomBrick> boomBricks;
    private ArrayList<PowerUp> pus;
    private int SIZE = 2;
    private final int W = 640 + (16 * SIZE);
    private final int H = 480;
    private User[] users;
    private final int SLEEPTIME = 50;
    private final String HOST = "localhost";
    
    
    public void init() {
        bg = new BomberGraphics(HOST, W, H, SIZE);
        setSize(W, H);
        setBackground(Color.GREEN);
        offscreen = createImage(W, H);
        og = offscreen.getGraphics();
        addKeyListener(this);
        bombs = new ArrayList<Bomb>();
        booms = new ArrayList<Boom>();
        pus = new ArrayList<PowerUp>();
        users = new User[4];
        me = new User();
        connector = new Connector(this, HOST);
        boomBricks = new ArrayList<BoomBrick>();
        new Run().start();
    }

    public void paint(Graphics g) {
        g.drawImage(offscreen, 0, 0, this);
    }

    public void update(Graphics g) {
        paint(g);
    }

    public void keyReleased(KeyEvent e) {
        if (!me.dead() && e.getKeyCode() - KeyEvent.VK_LEFT == me.way()) {
            stopWalk(me.id(), me.x(), me.y());
            int[] all = {7, me.x(), me.y()};
            connector.send(all);
        }
    }

    public void keyPressed(KeyEvent e) {
        if (!me.dead() && e.getKeyCode() >= KeyEvent.VK_LEFT && e.getKeyCode() <= KeyEvent.VK_DOWN && (me.way() != (e.getKeyCode() - KeyEvent.VK_LEFT) || !me.walk())) {
            startWalk(me.id(), e.getKeyCode() - KeyEvent.VK_LEFT, me.x(), me.y());
            int[] all = {5, e.getKeyCode() - KeyEvent.VK_LEFT, me.x(), me.y()};
            connector.send(all);
        } else if (!me.dead() && e.getKeyCode() == KeyEvent.VK_SPACE) {
            int[] all = { 9, me.x(), me.y() };
            connector.send(all);
        }
    }

    public boolean walk1(int x, int y) {
        return (walk[x][y] == 0);
    }

    public boolean walk2(int pixelX, int pixelY) {
        return walk1(pixelX / (16 * SIZE), pixelY / (16 * SIZE));
    }

    public void keyTyped(KeyEvent e) {     
    }

    private class Run extends Thread {

        public void run() {
            load();
            if (!connector.connect()) {
                og.drawString("Oh by the way: ERROR!", 0, 10);
                repaint();
            } else {
                long ms = System.currentTimeMillis();
                int time = SLEEPTIME;
                while (true) {
                    try {
                        
                        ms = System.currentTimeMillis();
                        Thread.sleep(time);
                        ms = System.currentTimeMillis() - ms;
                        if (ms > SLEEPTIME) time--;
                        else if (ms < SLEEPTIME) time++;
                        System.out.println(ms);
                        ms = System.currentTimeMillis();
                        
                    } catch (Exception e) {
                    }
                    og.drawImage(map, 0, 0, null);
                    bombs();
                    booms();
                    boomBricks();
                    pus();
                    for (int i = 0; i < users.length; i++) {
                        User u = users[i];
                        if (u != null && !u.dead()) {
                            move(u);
                            og.drawImage(bg.man(u.way(), u.anim()), u.x(), u.y() - (4 * SIZE), null);
                        }
                    }
                    repaint();
                }
            }
        }

        public void bombs() {
            for (int i = 0; i < bombs.size(); i++) {
                Bomb b = bombs.get(i);
                if (b.boom()) {
                    int x = b.x() / (16 * SIZE);
                    int y = b.y() / (16 * SIZE);
                    walk[x][y] = 0;
                    bombs.remove(b);

                    placeBoom(x, y, b.x(), b.y(), b.size());

                    i--;
                } else {
                    og.drawImage(bg.bomb(b.anim()), b.x(), b.y(), null);
                }
            }
        }

        public void placeBoom(int x, int y, int x2, int y2, int size) {
            booms.add(new Boom(x2, y2, 0));
            boolean[] stop = new boolean[4];
            for (int j = 1; j <= size; j++) {
                for (int n = 0; n < 4; n++) {
                    int x4 = x;
                    int y4 = y;
                    if (n == 0) {
                        x4 += j;
                    } else if (n == 1) {
                        y4 += j;
                    } else if (n == 2) {
                        x4 -= j;
                    } else {
                        y4 -= j;
                    }

                    int x3 = x4 * 16 * SIZE;
                    int y3 = y4 * 16 * SIZE;
                    if (x4 >= 0 && x4 < walk.length && y4 >= 0 && y4 < walk[0].length) {
                        switch (walk[x4][y4]) {
                            case 0:
                                if (!stop[n]) {
                                    int img = n % 2 + 1;
                                    if (j == size) {
                                        img = 3 + n;
                                    }
                                    booms.add(new Boom(x3, y3, img));
                                }
                                break;
                            case 1:
                                stop[n] = true;
                                break;
                            case 2:
                                if (!stop[n]) {
                                    stop[n] = true;
                                    boomBricks.add(new BoomBrick(x3, y3));
                                    if (first()) {
                                        int[] all = { 11, x4, y4 };
                                        connector.send(all);
                                    }
                                    walk[x4][y4] = 0;
                                    map = bg.clearRect(map, x3, y3);
                                }
                                break;
                            case 3:
                                stop[n] = true;
                                walk[x][y] = 1;
                                for (Bomb b : bombs) {
                                    if (b.x() == x3 && b.y() == y3) {
                                        b.explode();
                                    }
                                }
                            default:
                                if (!stop[0]) {

                                }
                        }
                    }
                }
            }
        }

        public boolean isBrick(int x, int y) {
            return true;
        }

        public void booms() {
            for (int i = 0; i < booms.size(); i++) {
                Boom b = booms.get(i);
                int anim = b.anim();
                if (anim < 4) {
                    og.drawImage(bg.boom(anim, b.boomImage()), b.x(), b.y(), null);
                    if (!me.dead() && me.x() / (16 * SIZE) == b.x() / (16 * SIZE) && me.y() / (16 * SIZE) == b.y() / (16 * SIZE)) {
                        int[] all = { 13 };
                        connector.send(all);
                        me.dead(true);
                    }
                } else {
                    walk[b.x() / (16 * SIZE)][b.y() / (16 * SIZE)] = 0;
                    booms.remove(b);
                    i--;
                }
            }
        }

        public void boomBricks() {
            for (int i = 0; i < boomBricks.size(); i++) {
                BoomBrick b = boomBricks.get(i);
                int anim = b.anim();
                if (anim < 2) {
                    og.drawImage(bg.boomBrick(anim), b.x(), b.y(), null);
                } else {
                    i--;
                    boomBricks.remove(b);
                }
            }
        }

        public void pus() {
            for (int i = 0; i < pus.size(); i++) {
                PowerUp pu = pus.get(i);
                og.drawImage(bg.pu(pu.pu()), pu.x(), pu.y(), null);
                for (int j = 0; j < users.length; j++) {
                    User u = users[j];
                    if (u != null && !u.dead()) {
                        if (u.x() > pu.x() - (16 * SIZE) && u.x() < pu.x() + (16 * SIZE) && u.y() > pu.y() - (16 * SIZE) && u.y() < pu.y() + (16 * SIZE)) {
                            switch (pu.pu()) {
                                case 0:
                                    u.size(u.size() + 1);
                                    break;
                            }


                            pus.remove(pu);

                            i--;
                        }
                    }
                }
            }
        }

        public void move(User u) {
            if (u.walk()) {
                int x, y, x2, y2;
                int x1, y1;
                switch (u.way()) {
                    case 0:
                        if (u.x() - u.speed() <= 0) {
                            break;
                        }
                        x1 = (u.x() + (8 * SIZE)) / (16 * SIZE);
                        x = (u.x() - u.speed()) / (16 * SIZE);
                        y = u.y() / (16 * SIZE);
                        y2 = ((u.y() - 1) + (16 * SIZE)) / (16 * SIZE);
                        if (!walk1(x, y) && !walk1(x, y2)) {
                            ;
                        } else if (!walk1(x, y)) {
                            u.down();
                        } else if (!walk1(x, y2)) {
                            u.up();
                        } else {
                            u.left();
                        }
                        if (x1 == x && walk[x][y] == 3) {
                            u.left();
                        }
                        break;
                    case 1:
                        if (u.y() - u.speed() <= 0) {
                            break;
                        }
                        y1 = (u.y() + (8 * SIZE)) / (16 * SIZE);
                        x = u.x() / (16 * SIZE);
                        y = (u.y() - u.speed()) / (16 * SIZE);
                        x2 = ((u.x() - 1) + (16 * SIZE)) / (16 * SIZE);
                        if (!walk1(x, y) && !walk1(x2, y)) {
                            ;
                        } else if (!walk1(x, y)) {
                            u.right();
                        } else if (!walk1(x2, y)) {
                            u.left();
                        } else {
                            u.up();
                        }
                        if (y1 == y && walk[x][y] == 3) {
                            u.up();
                        }
                        break;
                    case 2:
                        if (u.x() + u.speed() + (16 * SIZE) >= W) {
                            break;
                        }
                        x1 = (u.x() + (8 * SIZE)) / (16 * SIZE);
                        x = (u.x() + u.speed() - 1 + (16 * SIZE)) / (16 * SIZE);
                        y = u.y() / (16 * SIZE);
                        y2 = ((u.y() - 1) + (16 * SIZE)) / (16 * SIZE);
                        if (!walk1(x, y) && !walk1(x, y2)) {
                            ;
                        } else if (!walk1(x, y)) {
                            u.down();
                        } else if (!walk1(x, y2)) {
                            u.up();
                        } else {
                            u.right();
                        }
                        if (x1 == x && walk[x][y] == 3) {
                            u.right();
                        }
                        break;
                    case 3:
                        if (u.y() + u.speed() + (16 * SIZE) >= H) {
                            break;
                        }
                        y1 = (u.y() + (8 * SIZE)) / (16 * SIZE);
                        x = u.x() / (16 * SIZE);
                        y = (u.y() + u.speed() - 1 + (16 * SIZE)) / (16 * SIZE);
                        x2 = ((u.x() - 1) + (16 * SIZE)) / (16 * SIZE);
                        if (!walk1(x, y) && !walk1(x2, y)) {
                            ;
                        } else if (!walk1(x, y)) {
                            u.right();
                        } else if (!walk1(x2, y)) {
                            u.left();
                        } else {
                            u.down();
                        }
                        if (y1 == y && walk[x][y] == 3) {
                            u.down();
                        }
                        break;
                }
                u.animate();
            }
        }
        public void load() {
            og.drawImage(bg.download("bg.png"), 0, 0, W, H, null);
            repaint();
            bg.load();
        }
    }

    public void addUser(User user) {
        users[user.id()] = user;
    }

    public void size(int size) {
    // SIZE = size;
    }

    public void walk(Integer[][] walk) {
        this.walk = walk;
        map = bg.drawMap(walk);
    }

    public void setMe(int i) {
        me = users[i];
    }

    public void startWalk(int u, int way, int x, int y) {
        users[u].pos(x, y);
        users[u].way(way);
        users[u].walk(true);
    }

    public void stopWalk(int u, int x, int y) {
        users[u].pos(x, y);
        users[u].anim(0);
        users[u].walk(false);
    }

    public void placeBomb(int u, int x, int y) {
        User user = users[u];
        x = (x + (8 * SIZE)) / (16 * SIZE);
        y = (y + (8 * SIZE)) / (16 * SIZE);
        if (walk1(x, y)) {
            bombs.add(new Bomb(x * 16 * SIZE, y * 16 * SIZE, user.size()));
            walk[x][y] = 3;
        }
    }

    public void remove(int u) {
        users[u] = null;
    }

    public void dead(int u) {
        users[u].dead(true);
    }

    public boolean first() {
        for (int i = 0; i < users.length; i++) {
            if (users[i] != null) {
                if (users[i].equals(me)) {
                    return true;
                } else {
                    return false;
                }
            }
        }
        return false;
    }

    public void addPu(int pu, int x, int y) {
        pus.add(new PowerUp(pu, x * 16 * SIZE, y * 16 * SIZE));
    }
}
